/**
  ******************************************************************************
  * @file    app_mb_example.c
  * @author  Iron
  * @date    2021-02-06
  * @version v1.0
  * @brief   app_mb_example c file
  */

/* Private includes ----------------------------------------------------------*/
#include "shell-serial.h"
#include <lightmodbus/lightmodbus.h>
#include <lightmodbus/slave.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static ModbusMaster mb_master;
static ModbusSlave mb_slave;

//Registers and coils
static uint8_t coils[2] = { 0 };
static uint16_t regs[32] = { 0 };

//For storing exit codes
uint8_t sec, mec;

/* Private function prototypes -----------------------------------------------*/

//Dump slave information
void slavedump(int (*shell_printf)(const char *fmt, ...))
{
    int i;
    shell_printf("==SLAVE DUMP==" SHELL_END_OF_LINE);

    shell_printf("Registers:");
    for (i = 0; i < mb_slave.registerCount; i++)
        shell_printf(" %d", mb_slave.registers[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Coils:");
    for (i = 0; i < mb_slave.coilCount >> 3; i++)
        shell_printf(" %d", mb_slave.coils[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Request:");
    for (i = 0; i < mb_slave.request.length; i++)
        shell_printf(" %d", mb_slave.request.frame[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Response:");
    for (i = 0; i < mb_slave.response.length; i++)
        shell_printf(" %d", mb_slave.response.frame[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Exit code: %d" SHELL_END_OF_LINE, sec);
}

//Dump master information
void masterdump(int (*shell_printf)(const char *fmt, ...))
{
    int i;
    shell_printf("==MASTER DUMP==" SHELL_END_OF_LINE);

    shell_printf("Received data: slave: %d, addr: %d, count: %d, type: %d",
                 mb_master.data.address, mb_master.data.index, mb_master.data.count, mb_master.data.type);

    shell_printf("\t\tvalues:");

    switch (mb_master.data.type)
    {
    case MODBUS_HOLDING_REGISTER:
    case MODBUS_INPUT_REGISTER:
        for (i = 0; i < mb_master.data.count; i++)
            shell_printf(" %d", mb_master.data.regs[i]);
        break;

    case MODBUS_COIL:
    case MODBUS_DISCRETE_INPUT:
        for (i = 0; i < mb_master.data.count; i++)
            shell_printf(" %d", modbusMaskRead(mb_master.data.coils, mb_master.data.length, i));
        break;
    }

    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Request:");
    for (i = 0; i < mb_master.request.length; i++)
        shell_printf(" %d", mb_master.request.frame[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Response:");
    for (i = 0; i < mb_master.response.length; i++)
        shell_printf(" %d", mb_master.response.frame[i]);
    shell_printf(SHELL_END_OF_LINE);

    shell_printf("Exit code: %d" SHELL_END_OF_LINE, mec);
}

char app_mb_test(shell_context_t *shell, char *args)
{
    //Init slave (input registers and discrete inputs work just the same)
    mb_slave.address = 27;
    mb_slave.registers = regs;
    mb_slave.registerCount = 32;
    mb_slave.coils = coils;
    mb_slave.coilCount = 16;
    modbusSlaveInit(&mb_slave);

    //Init master
    modbusMasterInit(&mb_master);

    //Dump status
    slavedump(shell->shell_printf);
    masterdump(shell->shell_printf);

    /* WRITE VALUE */

    //Build frame to write single register
    modbusBuildRequest06(&mb_master, 27, 03, 56);

    //Pretend frame is being sent to slave
    mb_slave.request.frame = mb_master.request.frame;
    mb_slave.request.length = mb_master.request.length;

    //Let slave parse frame
    sec = modbusParseRequest(&mb_slave);

    //Pretend frame is being sent to master
    mb_master.response.frame = mb_slave.response.frame;
    mb_master.response.length = mb_slave.response.length;

    //Let master parse the frame
    mec = modbusParseResponse(&mb_master);

    //Dump status again
    slavedump(shell->shell_printf);
    masterdump(shell->shell_printf);

    
    /* READ VALUE */

    //Build frame to read 4 registers
    modbusBuildRequest03(&mb_master, 27, 0, 4);

    //Pretend frame is being sent to slave
    mb_slave.request.frame = mb_master.request.frame;
    mb_slave.request.length = mb_master.request.length;

    //Let slave parse frame
    sec = modbusParseRequest(&mb_slave);

    //Pretend frame is being sent to master
    mb_master.response.frame = mb_slave.response.frame;
    mb_master.response.length = mb_slave.response.length;

    mec = modbusParseResponse(&mb_master);

    //Dump status again
    slavedump(shell->shell_printf);
    masterdump(shell->shell_printf);


    /* COILS */

    //Build frame to write single coil
    modbusBuildRequest05(&mb_master, 27, 07, 1);

    //Pretend frame is being sent to slave
    mb_slave.request.frame = mb_master.request.frame;
    mb_slave.request.length = mb_master.request.length;

    //Let slave parse frame
    sec = modbusParseRequest(&mb_slave);

    //Pretend frame is being sent to master
    mb_master.response.frame = mb_slave.response.frame;
    mb_master.response.length = mb_slave.response.length;

    mec = modbusParseResponse(&mb_master);

    //Dump status again
    slavedump(shell->shell_printf);
    masterdump(shell->shell_printf);

    /* READ VALUE */

    //Build frame to read 4 coils
    modbusBuildRequest01(&mb_master, 27, 0, 8);

    //Pretend frame is being sent to slave
    mb_slave.request.frame = mb_master.request.frame;
    mb_slave.request.length = mb_master.request.length;

    //Let slave parse frame
    sec = modbusParseRequest(&mb_slave);

    //Pretend frame is being sent to master
    mb_master.response.frame = mb_slave.response.frame;
    mb_master.response.length = mb_slave.response.length;

    mec = modbusParseResponse(&mb_master);

    //Dump status again
    slavedump(shell->shell_printf);
    masterdump(shell->shell_printf);

    return NULL;
}


/**
  * @}
  */

/******************* (C)COPYRIGHT 2021 ***** END OF FILE *********************/
